home *** CD-ROM | disk | FTP | other *** search
/ PC World 2007 June / PCWorld_2007-06_cd.bin / temacd / wikipad / WikidPad-1.9beta2.exe / {app} / extensions / GraphvizClBridge.py < prev    next >
Text File  |  2007-02-24  |  12KB  |  310 lines

  1. import os, os.path
  2. from subprocess import list2cmdline
  3.  
  4. import wx
  5.  
  6. from pwiki.TempFileSet import createTempFile
  7. from pwiki.StringOps import mbcsEnc, mbcsDec, lineendToOs
  8.  
  9. WIKIDPAD_PLUGIN = (("InsertionByKey", 1), ("Options", 1))
  10.  
  11. def describeInsertionKeys(ver, app):
  12.     """
  13.     API function for "InsertionByKey" plugins
  14.     Returns a sequence of tuples describing the supported
  15.     insertion keys. Each tuple has the form (insKey, exportTypes, handlerFactory)
  16.     where insKey is the insertion key handled, exportTypes is a sequence of
  17.     strings describing the supported export types and handlerFactory is
  18.     a factory function (normally a class) taking the wxApp object as
  19.     parameter and returning a handler object fulfilling the protocol
  20.     for "insertion by key" (see EqnHandler as example).
  21.  
  22.     ver -- API version (can only be 1 currently)
  23.     app -- wxApp object
  24.     """
  25.     return (
  26.             (u"dot", ("html_single", "html_previewWX", "html_preview", "html_multi"), DotHandler),
  27.             (u"neato", ("html_single", "html_previewWX", "html_preview", "html_multi"), NeatoHandler),
  28.             (u"twopi", ("html_single", "html_previewWX", "html_preview", "html_multi"), TwopiHandler),
  29.             (u"circo", ("html_single", "html_previewWX", "html_preview", "html_multi"), CircoHandler),
  30.             (u"fdp", ("html_single", "html_previewWX", "html_preview", "html_multi"), FdpHandler)
  31.             )
  32.  
  33.  
  34. class GraphVizBaseHandler:
  35.     """
  36.     Base class fulfilling the "insertion by key" protocol.
  37.     """
  38.     # Filled in by derived classes
  39.     EXAPPNAME = ""
  40.     EXECONFIGKEY = ""
  41.     
  42.     def __init__(self, app):
  43.         self.app = app
  44.         self.extAppExe = None
  45.         
  46.     def taskStart(self, exporter, exportType):
  47.         """
  48.         This is called before any call to createContent() during an
  49.         export task.
  50.         An export task can be a single HTML page for
  51.         preview or a single page or a set of pages for export.
  52.         exporter -- Exporter object calling the handler
  53.         exportType -- string describing the export type
  54.         
  55.         Calls to createContent() will only happen after a 
  56.         call to taskStart() and before the call to taskEnd()
  57.         """
  58.         # Find MimeTeX executable by configuration setting
  59.         dirPath = self.app.getGlobalConfig().get("main",
  60.                 "plugin_graphViz_dirExe", "")
  61.         if not dirPath:
  62.             self.extAppExe = ""
  63.             return
  64.             
  65.         exeName = self.app.getGlobalConfig().get("main", self.EXECONFIGKEY, "")
  66.         self.extAppExe = os.path.join(dirPath, exeName)
  67.  
  68.         
  69.     def taskEnd(self):
  70.         """
  71.         Called after export task ended and after the last call to
  72.         createContent().
  73.         """
  74.         pass
  75.  
  76.  
  77.     def createContent(self, exporter, exportType, insToken):
  78.         """
  79.         Handle an insertion and create the appropriate content.
  80.  
  81.         exporter -- Exporter object calling the handler
  82.         exportType -- string describing the export type
  83.         insToken -- insertion token to create content for (see also 
  84.                 PageAst.Insertion)
  85.  
  86.         An insertion token has the following member variables:
  87.             key: insertion key (unistring)
  88.             value: value of an insertion (unistring)
  89.             appendices: sequence of strings with the appendices
  90.  
  91.         Meaning and type of return value is solely defined by the type
  92.         of the calling exporter.
  93.         
  94.         For HtmlXmlExporter a unistring is returned with the HTML code
  95.         to insert instead of the insertion.        
  96.         """
  97.         # Retrieve quoted content of the insertion
  98.         bstr = lineendToOs(mbcsEnc(insToken.value, "replace")[0])
  99.  
  100.         if not bstr:
  101.             # Nothing in, nothing out
  102.             return u""
  103.         
  104.         if self.extAppExe == "":
  105.             # No path to MimeTeX executable -> show message
  106.             return "<pre>[Please set path to GraphViz executables]</pre>"
  107.  
  108.         # Get exporters temporary file set (manages creation and deletion of
  109.         # temporary files)
  110.         tfs = exporter.getTempFileSet()
  111.  
  112.         pythonUrl = (exportType != "html_previewWX")
  113.         dstFullPath = tfs.createTempFile("", ".png", relativeTo="")
  114.         url = tfs.getRelativeUrl(None, dstFullPath, pythonUrl=pythonUrl)
  115.  
  116.         # Store token content in a temporary file
  117.         srcfilepath = createTempFile(bstr, ".dot")
  118.         try:
  119.             cmdline = list2cmdline((self.extAppExe, "-Tpng", "-o" + dstFullPath,
  120.                     srcfilepath))
  121.  
  122.             # Run external application
  123.             childIn, childOut, childErr = os.popen3(cmdline, "b")
  124.  
  125.             if u"noerror" in [a.strip() for a in insToken.appendices]:
  126.                 childErr.read()
  127.                 errResponse = ""
  128.             else:
  129.                 errResponse = childErr.read()
  130.         finally:
  131.             os.unlink(srcfilepath)
  132.             
  133.         if errResponse != "":
  134.             appname = mbcsDec(self.EXAPPNAME, "replace")[0]
  135.             errResponse = mbcsDec(errResponse, "replace")[0]
  136.             return u"<pre>[%s Error: %s]</pre>" % (appname, errResponse)
  137.  
  138.  
  139.         # Return appropriate HTML code for the image
  140.         if exportType == "html_previewWX":
  141.             # Workaround for internal HTML renderer
  142.             return u'<img src="%s" border="0" align="bottom" /> ' % url
  143.         else:
  144.             return u'<img src="%s" border="0" align="bottom" />' % url
  145.  
  146.  
  147.     def getExtraFeatures(self):
  148.         """
  149.         Returns a list of bytestrings describing additional features supported
  150.         by the plugin. Currently not specified further.
  151.         """
  152.         return ()
  153.         
  154.  
  155.  
  156. class DotHandler(GraphVizBaseHandler):
  157.     EXAPPNAME = "Dot"
  158.     EXECONFIGKEY = "plugin_graphViz_exeDot"
  159.  
  160. class NeatoHandler(GraphVizBaseHandler):
  161.     EXAPPNAME = "Neato"
  162.     EXECONFIGKEY = "plugin_graphViz_exeNeato"
  163.  
  164. class TwopiHandler(GraphVizBaseHandler):
  165.     EXAPPNAME = "Twopi"
  166.     EXECONFIGKEY = "plugin_graphViz_exeTwopi"
  167.  
  168. class CircoHandler(GraphVizBaseHandler):
  169.     EXAPPNAME = "Circo"
  170.     EXECONFIGKEY = "plugin_graphViz_exeCirco"
  171.  
  172. class FdpHandler(GraphVizBaseHandler):
  173.     EXAPPNAME = "Fdp"
  174.     EXECONFIGKEY = "plugin_graphViz_exeFdp"
  175.  
  176.  
  177. def registerOptions(ver, app):
  178.     """
  179.     API function for "Options" plugins
  180.     Register configuration options and their GUI presentation
  181.     ver -- API version (can only be 1 currently)
  182.     app -- wxApp object
  183.     """
  184.     # Register options
  185.     app.getDefaultGlobalConfigDict()[("main", "plugin_graphViz_dirExe")] = u""
  186.  
  187.     app.getDefaultGlobalConfigDict()[("main", "plugin_graphViz_exeDot")] = u"dot.exe"
  188.     app.getDefaultGlobalConfigDict()[("main", "plugin_graphViz_exeNeato")] = u"neato.exe"
  189.     app.getDefaultGlobalConfigDict()[("main", "plugin_graphViz_exeTwopi")] = u"twopi.exe"
  190.     app.getDefaultGlobalConfigDict()[("main", "plugin_graphViz_exeCirco")] = u"circo.exe"
  191.     app.getDefaultGlobalConfigDict()[("main", "plugin_graphViz_exeFdp")] = u"fdp.exe"
  192.  
  193.     # Register panel in options dialog
  194.     app.addOptionsDlgPanel(GraphVizOptionsPanel, u"  GraphViz")
  195.  
  196.  
  197. class GraphVizOptionsPanel(wx.Panel):
  198.     def __init__(self, parent, optionsDlg, app):
  199.         """
  200.         Called when "Options" dialog is opened to show the panel.
  201.         Transfer here all options from the configuration file into the
  202.         text fields, check boxes, ...
  203.         """
  204.         wx.Panel.__init__(self, parent)
  205.         self.app = app
  206.         
  207.         pt = self.app.getGlobalConfig().get("main", "plugin_graphViz_dirExe",
  208.                 u"")
  209.         self.tfDir = wx.TextCtrl(self, -1, pt)
  210.  
  211.         pt = self.app.getGlobalConfig().get("main", "plugin_graphViz_exeDot",
  212.                 u"dot.exe")
  213.         self.tfDot = wx.TextCtrl(self, -1, pt)
  214.  
  215.         pt = self.app.getGlobalConfig().get("main", "plugin_graphViz_exeNeato",
  216.                 u"neato.exe")
  217.         self.tfNeato = wx.TextCtrl(self, -1, pt)
  218.  
  219.         pt = self.app.getGlobalConfig().get("main", "plugin_graphViz_exeTwopi",
  220.                 u"twopi.exe")
  221.         self.tfTwopi = wx.TextCtrl(self, -1, pt)
  222.  
  223.         pt = self.app.getGlobalConfig().get("main", "plugin_graphViz_exeCirco",
  224.                 u"circo.exe")
  225.         self.tfCirco = wx.TextCtrl(self, -1, pt)
  226.  
  227.         pt = self.app.getGlobalConfig().get("main", "plugin_graphViz_exeFdp",
  228.                 u"fdp.exe")
  229.         self.tfFdp = wx.TextCtrl(self, -1, pt)
  230.  
  231.         mainsizer = wx.FlexGridSizer(6, 2, 0, 0)
  232.         mainsizer.AddGrowableCol(1, 1)
  233.  
  234.         mainsizer.Add(wx.StaticText(self, -1, "Directory of executables:"), 0,
  235.                 wx.ALL | wx.EXPAND, 5)
  236.         mainsizer.Add(self.tfDir, 1, wx.ALL | wx.EXPAND, 5)
  237.  
  238.         mainsizer.Add(wx.StaticText(self, -1, "Name of dot executable:"), 0,
  239.                 wx.ALL | wx.EXPAND, 5)
  240.         mainsizer.Add(self.tfDot, 1, wx.ALL | wx.EXPAND, 5)
  241.  
  242.         mainsizer.Add(wx.StaticText(self, -1, "Name of neato executable:"), 0,
  243.                 wx.ALL | wx.EXPAND, 5)
  244.         mainsizer.Add(self.tfNeato, 1, wx.ALL | wx.EXPAND, 5)
  245.  
  246.         mainsizer.Add(wx.StaticText(self, -1, "Name of twopi executable:"), 0,
  247.                 wx.ALL | wx.EXPAND, 5)
  248.         mainsizer.Add(self.tfTwopi, 1, wx.ALL | wx.EXPAND, 5)
  249.  
  250.         mainsizer.Add(wx.StaticText(self, -1, "Name of circo executable:"), 0,
  251.                 wx.ALL | wx.EXPAND, 5)
  252.         mainsizer.Add(self.tfCirco, 1, wx.ALL | wx.EXPAND, 5)
  253.  
  254.         mainsizer.Add(wx.StaticText(self, -1, "Name of fdp executable:"), 0,
  255.                 wx.ALL | wx.EXPAND, 5)
  256.         mainsizer.Add(self.tfFdp, 1, wx.ALL | wx.EXPAND, 5)
  257.  
  258.         self.SetSizer(mainsizer)
  259.         self.Fit()
  260.  
  261.     def setVisible(self, vis):
  262.         """
  263.         Called when panel is shown or hidden. The actual wxWindow.Show()
  264.         function is called automatically.
  265.         
  266.         If a panel is visible and becomes invisible because another panel is
  267.         selected, the plugin can veto by returning False.
  268.         When becoming visible, the return value is ignored.
  269.         """
  270.         return True
  271.  
  272.     def checkOk(self):
  273.         """
  274.         Called when "OK" is pressed in dialog. The plugin should check here if
  275.         all input values are valid. If not, it should return False, then the
  276.         Options dialog automatically shows this panel.
  277.         
  278.         There should be a visual indication about what is wrong (e.g. red
  279.         background in text field). Be sure to reset the visual indication
  280.         if field is valid again.
  281.         """
  282.         return True
  283.  
  284.     def handleOk(self):
  285.         """
  286.         This is called if checkOk() returned True for all panels. Transfer here
  287.         all values from text fields, checkboxes, ... into the configuration
  288.         file.
  289.         """
  290.         pt = self.tfDir.GetValue()
  291.         self.app.getGlobalConfig().set("main", "plugin_graphViz_dirExe", pt)
  292.  
  293.         pt = self.tfDot.GetValue()
  294.         self.app.getGlobalConfig().set("main", "plugin_graphViz_exeDot", pt)
  295.  
  296.         pt = self.tfNeato.GetValue()
  297.         self.app.getGlobalConfig().set("main", "plugin_graphViz_exeNeato", pt)
  298.  
  299.         pt = self.tfTwopi.GetValue()
  300.         self.app.getGlobalConfig().set("main", "plugin_graphViz_exeTwopi", pt)
  301.  
  302.         pt = self.tfCirco.GetValue()
  303.         self.app.getGlobalConfig().set("main", "plugin_graphViz_exeCirco", pt)
  304.  
  305.         pt = self.tfFdp.GetValue()
  306.         self.app.getGlobalConfig().set("main", "plugin_graphViz_exeFdp", pt)
  307.  
  308.  
  309.  
  310.